<template>
  <div ref="editor" class="main"></div>
</template>

<script>
import * as monaco from 'monaco-editor'
import createSqlCompleter from './util/sql-completion'
import createJavascriptCompleter from './util/javascript-completion'
import registerLanguage from './util/log-language'
const global = {}

const getHints = model => {
  const id = model.id.substring(6)
  return (global[id] && global[id].hints) || []
}
monaco.languages.registerCompletionItemProvider(
  'sql',
  createSqlCompleter(getHints)
)
monaco.languages.registerCompletionItemProvider(
  'javascript',
  createJavascriptCompleter(getHints)
)
registerLanguage(monaco)
/**
 * monaco options
 * https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandaloneeditorconstructionoptions.html
 */
export default {
  props: {
    options: {
      type: Object,
      default() {
        return {}
      }
    },
    value: {
      type: String,
      required: false
    },
    language: {
      type: String
    },
    hints: {
      type: Array,
      default() {
        return []
      }
    }
  },
  name: 'MonacoEditor',
  data() {
    return {
      editorInstance: null,
      defaultOptions: {
        theme: 'vs-dark',
        fontSize: 14
      }
    }
  },
  watch: {
    value() {
      if (this.value !== this.editorInstance.getValue()) {
        this.editorInstance.setValue(this.value)
      }
    }
  },
  mounted() {
    this.initEditor()
    global[this.editorInstance._id] = this
    window.addEventListener('resize', this.layout)
  },
  destroyed() {
    this.editorInstance.dispose()
    global[this.editorInstance._id] = null
    window.removeEventListener('resize', this.layout)
  },
  methods: {
    layout() {
      this.editorInstance.layout()
    },
    undo() {
      this.editorInstance.trigger('anyString', 'undo')
      this.onValueChange()
    },
    redo() {
      this.editorInstance.trigger('anyString', 'redo')
      this.onValueChange()
    },
    getOptions() {
      const props = { value: this.value }
      this.language !== undefined && (props.language = this.language)
      const options = Object.assign({}, this.defaultOptions, this.options, props)
      return options
    },
    onValueChange() {
      this.$emit('input', this.editorInstance.getValue())
      this.$emit('change', this.editorInstance.getValue())
    },
    initEditor() {
      this.MonacoEnvironment = {
        getWorkerUrl: function() {
          return './editor.worker.bundle.js'
        }
      }

      this.editorInstance = monaco.editor.create(
        this.$refs.editor,
        this.getOptions()
      )
      this.editorInstance.onContextMenu(e => {
        this.$emit('contextmenu', e)
      })
      this.editorInstance.onDidChangeModelContent(() => {
        this.onValueChange()
      })
      this.editorInstance.addCommand(
        monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S,
        () => {
          this.$emit('save', this.editorInstance.getValue())
        }
      )
    }
  }
}
</script>

<style scoped>
.main /deep/ .view-lines * {
  font-family: Consolas, "Courier New", monospace !important;
}
</style>
